home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / c / c-bat-0.1n / c-bat-0 / c-bat-0.1 / src / intrface.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-16  |  53.6 KB  |  1,786 lines

  1. /*
  2.     intrface : Browsing an Analysis Tool for C-source code;
  3.                Interface-Module for Server and Clients,
  4.                distinguished by defining BRS_SERVER 
  5.  
  6.     Copyright (C) 1993  Eckehard Stolz
  7.  
  8.     This program is free software; you can redistribute it and/or modify
  9.     it under the terms of the GNU General Public License as published by
  10.     the Free Software Foundation (version 2 of the License).
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <signal.h>
  26. #include <unistd.h>
  27. #include <errno.h>
  28. #include <sys/ipc.h>
  29. #include <sys/msg.h>
  30.  
  31. #include "c-bat.h"
  32.  
  33.  
  34. /* On SUN's the strerror seems to be missing !
  35.  
  36.    Here is a substitution !
  37.  
  38.    (by Paul T. Keener keener@upenn5.hep.upenn.edu) 
  39.  */
  40. #ifdef NO_STRERROR
  41. /*
  42.  * strerror for those machines that don't provide it
  43.  */
  44.  
  45. extern char *sys_errlist[];
  46.  
  47. char *strerror( int errnum )
  48. {
  49.  
  50.         return sys_errlist[errnum];
  51.  
  52. }
  53. #endif
  54.  
  55.  
  56. /*
  57.  
  58.   Interfacing between frontend and browser-engine is done by a
  59.   maximaum INTRFACE_BUFFER (1KB) message.
  60.  
  61.   Message-Type: Server-ID (at the moment: SERVER_ID1 (c-bat.h)
  62.  
  63.   maximum stringsize: STRINGSIZE
  64.  
  65.   structure of message:
  66.  
  67.   Offset    Type     Meaning
  68.   (Bytes)
  69.  
  70.     0       short    Command
  71.  
  72.     2       short    Additional Flags
  73.  
  74.     4       int      PID of Client
  75.  
  76.     8       long     ID of message (mainly for debugging purposes)
  77.  
  78.    12       char []  Command-Arguments, separated by ","
  79.  
  80.  
  81.   Commands: from frontend-module to browser-engine
  82.             <ident>  ...  indentifier of function or module
  83.             [ ]      ...  argument is optional
  84.  
  85.       Note: the ..._ONCE-commands work like the corresponding commands
  86.             except that every symbol is just printed once !
  87.  
  88.    CMD_INIT          Init the Browser,
  89.                      Arguments: <Browser-File>
  90.  
  91.    CMD_CALLS         Get function-calls of a target-function
  92.                      Arguments: <target-funct> [,<target-funct-file>]
  93.  
  94.    CMD_CALLED_BY     Get functions that call target-function
  95.                      Arguments: <target-funct> [,<target-funct-file>]
  96.  
  97.    CMD_FUNCT_POS     Get position (file, line) of target-function
  98.                      Arguments: <target-funct> [,<target-funct-file>]
  99.  
  100.    CMD_VAR_POS       Get position (file, line) of target-variable (global)
  101.                      Arguments: <target-var> [,<target-funct-file>]
  102.  
  103.    CMD_USES          List usage of global variable in target-function
  104.                      Arguments: <target-funct> [,<target-funct-file>]
  105.  
  106.    CMD_USES_ALL      List usage of all variable in target-function
  107.                      Arguments: <target-funct> [,<target-funct-file>]
  108.  
  109.    CMD_USED_BY       List function that use target-variable
  110.                      Arguments: <target-var> [,<target-funct-file>]
  111.  
  112.    CMD_FILE          Return Module, where FILE belongs to
  113.                      Arguments: <filename>
  114.  
  115.    CMD_INCLUDES      Return Files, that are includes in that given file
  116.                      Arguments: <filename>
  117.  
  118.    CMD_FUNCTIONS     Return all functions defined in the project
  119.                      Arguments: none
  120.  
  121.    CMD_VARIABLES     Return all global (and static) variables defined in
  122.                      the project
  123.                      Arguments: none
  124.  
  125.    CMD_STRUCTS       Return all struct defined in the project
  126.                      Arguments: none
  127.  
  128.    CMD_UNIONS        Return all unions defined in the project
  129.                      Arguments: none
  130.  
  131.    CMD_ENUMS         Return all enums defined in the project
  132.                      Arguments: none
  133.  
  134.    CMD_TYPEDEFS      Return all typedefs defined in the project
  135.                      Arguments: none
  136.  
  137.    CMD_WHAT_IS       Return (possibly more than one) type(s) of unknown <item>
  138.                      Arguments: <unknown_item> [,<file_where_item_found>]
  139.  
  140.    CMD_INCLUDED_BY   Return files which include given file
  141.                      Arguments: <filename>
  142.    
  143.    CMD_REFERENCE     Usage of a struct component (global/file)
  144.                      Arguments: <component_name>[,<file>]
  145.    
  146.    CMD_REFERENCE_F   Usage of struct component in a function (no scope checking
  147.                      because we have only two arguments at the moment)
  148.                      Arguments: <component_name>,<function>
  149.    
  150.    CMD_REFERENCE_V   Usage of component and variable in same line
  151.                      Arguments: <component_name>,<variable>
  152.    
  153.    CMD_FILES         Return all files in project
  154.                      Arguments: none
  155.  
  156.    CMD_WORK_DIR      Return working directory of a file
  157.                      Arguments: <file>
  158.  
  159.    CMD_MACRO         Return all macro definitions in project
  160.                      Arguments: none
  161.  
  162.    
  163.    CMD_DEF_POS       Return definition position of item found at position
  164.                      file/line. File and Item is seperated by a '*'
  165.                      Arguments: <file*ident>,<line>
  166.  
  167.    Commands for Interfacing:
  168.  
  169.    CMD_CONNECT       Client tries to connect to Server
  170.                      Arguments: none
  171.  
  172.    CMD_RELEASE       Client tries to terminate connection to server
  173.                      Arguments: none
  174.  
  175.    CMD_TERMINATE     Client wants to kill server
  176.                      Arguments: none
  177.  
  178.    CMD_ABORT         Client aborts actual command (not implemented yet)
  179.                      Arguments: none
  180.    
  181.    CMD_SERVER        Send request for a server-ID to the master server
  182.                      Arguments: filename of browser-file
  183.    
  184.    CMD_MACRO_POS     Get position (file, line) of target-macro
  185.                      Arguments: <macro> [,<target-macro-file>]
  186.  
  187.  
  188.   structure of return-message:
  189.   ============================
  190.    
  191.   Message-Type:  32 Bit:  xxxx xxxx xxxx xxxx
  192.                           cmd  ----PID-------
  193.    
  194.    cmd:  Command which caused this return 0 - 0x7f)
  195.    PID:  client-pid & 0x00ffffff
  196.    
  197.   Offset    Type     Meaning
  198.   (Bytes)
  199.  
  200.     0       short    Command
  201.  
  202.     2       short    Additional Flags
  203.  
  204.     4       int      Server-ID
  205.  
  206.     8       long     ID of message (mainly for debugging purposes)
  207.  
  208.    12       char []  Command-Arguments, separated by ","
  209.  
  210.  
  211.   Return-Value: Value in command word specifies type, additional info
  212.                 in the flag word
  213.  
  214.    RET_FILE          Return a File and (optional) Module
  215.                      Arguments:  <filename> [,<modul_name>]
  216.                      Flag     :   0x01  ... 1: file is part of a Module
  217.                                             0: no module defined
  218.                      Flag     :   0x02  ... 1: File is system-header
  219.                                             0: File is user-header
  220.  
  221.                      Note: if RET_FILE is a Header-file, <module_name> is
  222.                            used to return the filename of the file, where
  223.                            <filename> is included by (might be another
  224.                            headerfile in case of nested includes)
  225.  
  226.    RET_DIR           Return a directory
  227.                      Arguments:  <dirname>
  228.  
  229.    RET_FUNCT         Return function-name and position
  230.                      Arguments: <funct>,<file>,<line> [,<module>]
  231.                      File and line can be empty, if definition position of
  232.                      function is unknown
  233.                      Flag     :   0x01  ... 1: position unknown
  234.                                             0: position given
  235.                                   0x02  ... 1: module given
  236.                                             0: no module specified
  237.                                   0x04  ... 1: function is static
  238.                                             0: function is global
  239.  
  240.  
  241.  
  242.    RET_VAR           Return variable-name and position
  243.                      Arguments: <var>,<file>,<line> [,<module>]
  244.                      File and line can be empty, if definition position of
  245.                      variable is unknown
  246.                      Flag     :   0x01  ... 1: position unknown
  247.                                             0: position given
  248.                                   0x02  ... 1: module given
  249.                                             0: no module specified
  250.                                   0x04  ... 1: variable is static
  251.                                             0: variable is global
  252.  
  253.    RET_L_VAR         Return local variable-name and position
  254.                      Arguments: <var>,<file>,<line>,<function>
  255.                      Flag     :   0x01  ... 1: position unknown
  256.                                             0: position given
  257.                                   0x04  ... 1: variable is formal parameter
  258.                                             0: variable is local
  259.  
  260.    RET_POS           Returns Position
  261.                      Arguments: <file>,<line> [,<module>]
  262.                      Flag     :   0x01  ... 1: module given
  263.                                             0: no module specified
  264.  
  265.    RET_FPOS          Returns Position of a function
  266.                      Arguments: <file>,<line>,<endline> [,<module>]
  267.                      Flag     :   0x01  ... 1: module given
  268.                                             0: no module specified
  269.  
  270.    RET_STRUCT        Returns struct-identifier
  271.                      Arguments: <struct>,<file>,<line>
  272.  
  273.    RET_UNION         Returns union-identifier
  274.                      Arguments: <union>,<file>,<line>
  275.  
  276.    RET_ENUM          Returns enum-type-identifier
  277.                      Arguments: <enum>,<file>,<line>
  278.  
  279.    RET_MACRO         Returns macro definition
  280.                      Arguments: <macro>,<file>,<line>
  281.  
  282.    RET_TYPEDEF       Returns typedef
  283.                      Arguments: <typedef>,<file>,<line>
  284.  
  285.    RET_E_CONST       Returns enum-constant
  286.                      Arguments: <enum-const>,<enum>,<file>,<line>
  287.  
  288.    RET_S_COMP        Returns component of struct
  289.                      Arguments: <component>,<struct>,<file>,<line>
  290.  
  291.    RET_U_COMP        Returns component of union
  292.                      Arguments: <component>,<union>,<file>,<line>
  293.  
  294.    RET_COMP          Returns component of struct or union
  295.                      Arguments: <component>,<file>,<line>
  296.  
  297.    RET_END           No more items found
  298.                      Arguments: none
  299.  
  300.    RET_ERROR         Specified items not found in symbol table or browser-file
  301.                      could not opened (if CMD was CMD_INIT)
  302.                      Arguments: <Error message1> [<Error message2>]
  303.                      Flag     :   0x01  ... 1: error message 2 given
  304.                                             0: just error message 1
  305.  
  306.  
  307.    RET_OK            Command successful if CMD was CMD_INIT
  308.                      Arguments: none
  309.  
  310.    RET_REFERENCE     File and line and function where struct component used
  311.                      Arguments: <file>,<line>,<function>
  312.  
  313.  
  314.  
  315.    Return-values for Interfacing
  316.  
  317.    RET_CONNECT       Connection client-server established
  318.                      Server tells client application a
  319.                      recommended timeout time (in seconds)
  320.                      Arguments: <timeout>
  321.  
  322.    RET_REFUSED       Connection client-server refused
  323.                      Arguments: String with message
  324.  
  325.    RET_PLEASE_WAIT   Server requests more time to finish task
  326.  
  327. ===================================================================
  328.  
  329. Special communication between multiple servers:
  330.  
  331. The first started server is the master and creates the message queue.
  332. Every next server - realizing that there is allready a message queue
  333. created - tries to request an unique ID from the master server.
  334.  
  335. Master server:
  336.   initalizes a table with all servers and their browser files.
  337.  
  338. Non Master Server:
  339.   sends the following command to the server:
  340.  
  341.   CMD_SERVER       Hi ! I'm a new server and like to have an own ID
  342.                    Arguments: browser filename
  343.  
  344.   and receives following: (to the ID: TMP_SERVER_ID)
  345.  
  346.   Mtext[0]:  new ID (instead of a return code)
  347.                    Arguments: browser filename (to check for correct recepient)
  348.  
  349.   If a server has to terminate and is not the master server, he tells the master
  350.   server to free his ID by sending:
  351.  
  352.   [0]  CMD_SERVERKILL
  353.   [4]  server ID
  354.  
  355. Clients can send a request to the master server to get the ID of the server
  356. which processes the requested browser file
  357.  
  358.   CMD_SERVER_ID      Return ID of the server with the following browser filename
  359.                      Arguments: browser filename
  360.  
  361. The master server sends following answer:
  362.  
  363.   RET_ERROR  ("Wrong Server" or "Unknown Browser file")
  364.  
  365.   RET_SERVER_ID   (id returned in flags)
  366.  
  367. If the master server dies and is the only one left, he removes the message queue.
  368. If there are other servers running, he sends the server table to an other server
  369. which takes over his part.
  370.  
  371. In this case, he sends the
  372.   CMD_SERVERTABLE command for each entry of the server table
  373.   [4]  server ID
  374.  
  375. and
  376.  
  377.   CMD_S_TABLE_END at the end of the table. In this case, the new server has to send
  378.   an acknowledgement by resending this message
  379.   [4]  server ID
  380.  */
  381.  
  382.  
  383.  
  384.  
  385. #define  INTRFACE_BUFSIZE  1024
  386.  
  387.  
  388. struct msgform {
  389.   long mtype;
  390.   char mtext[INTRFACE_BUFSIZE];
  391. };
  392.  
  393. static struct msgform  Msg; /* message buffer */
  394.  
  395. static key_t  key = DEFAULT_KEY;
  396. static int  msqid;
  397.  
  398.  
  399. static short first = 1;
  400.  
  401.  
  402. #ifdef BRS_SERVER
  403.  
  404. /* init function for server
  405.  */
  406. extern void  terminate_handler(int sig);
  407.  
  408. /* Tries to create IPC ressource. if one exists, it returns 0 idicating that
  409.    there is a ressource still left or that there is allready a master server
  410.    running. If the value of 1 is returned, this server is the master server !
  411.  */
  412. static int init_interface(void)
  413. {
  414.     first = 0;
  415.    
  416.     if ((msqid = msgget (key, 0777 | IPC_CREAT | IPC_EXCL)) == -1) {
  417.         switch( errno )
  418.           { case EEXIST: /* message queue does allready exist. Try to 
  419.                             connect to master */
  420.                  if ((msqid = msgget (key, 0777 )) == -1) {
  421.                      fprintf(stderr, "Init-Interface: msgget: errno: %d (%s)\n", 
  422.                                       errno, strerror(errno) );
  423.                  exit( 1 );
  424.                     }
  425.                  return(0);
  426.                  break;
  427.                
  428.             default:
  429.                fprintf(stderr, "Init-Interface: msgget: errno: %d (%s)\n", 
  430.                          errno, strerror(errno) );
  431.                exit( 1 );
  432.                break;
  433.            }
  434.       }
  435.     return( 1 );
  436. }
  437.  
  438. #else
  439.  
  440. /* Init function for client 
  441.    return value is "don't care"
  442.  */
  443. static int init_interface(void)
  444. {
  445.     first = 0;
  446.    
  447.     if ((msqid = msgget (key, 0777 )) == -1) {
  448.         fprintf(stderr, "Init-Interface: msgget: errno: %d (%s)\n", 
  449.                          errno, strerror(errno) );
  450.     exit( 1 );
  451.     }
  452.    return(0);
  453.  
  454.  }
  455. #endif
  456.  
  457. /* Debug-function: returns any message from message-queue
  458.  */
  459. short brs_get_any_message(int *type, short *cmd, short *flag, int *pid, long *id, char *buf)
  460. { int cnt;
  461.    
  462.   cnt = msgrcv( msqid, (struct msgbuf *) &Msg, 
  463.                  INTRFACE_BUFSIZE, 0, IPC_NOWAIT);
  464.    
  465.   if( cnt == -1 )
  466.    return(cnt);
  467.    
  468.   *cmd  = *((short *) Msg.mtext    );
  469.   *flag = *((short *) (Msg.mtext + 2) );
  470.   *pid  = *((int   *) (Msg.mtext + 4) );
  471.   *id   = *((long  *) (Msg.mtext + 8) );
  472.    
  473.   *type = Msg.mtype;
  474.    
  475.   strncpy( buf, Msg.mtext + ARGUMENT_OFFSET, INTRFACE_BUFSIZE - 8 );
  476.   return( cnt );
  477.  }
  478.   
  479.  
  480. /*********************************************************************
  481. **********************************************************************
  482.  
  483. THIS PART OF THE CODE ARE THE MAIN INTERFACING ROUTINES FOR THE SERVER
  484.  
  485. **********************************************************************
  486. *********************************************************************/
  487.  
  488. #ifdef BRS_SERVER
  489.  
  490. /* struct for server-table. Every running server has a table which
  491.    holds the id's and the name of the browser file
  492. */
  493. struct server_table
  494. { int    server_id;
  495.   char  *filename;
  496.  };
  497.  
  498. short cnt_servers = MASTER_ID;
  499.  
  500. struct server_table s_table[MAX_SERVERS + MASTER_ID];
  501.  
  502. long  cmd_id = 0;
  503. long  ret_id = 0;
  504.  
  505. static int cmd_msg_flag; /* command used for selective message return */
  506.  
  507. /* time needed for initial scanning. Used to tell
  508.    clients minimum timeout-time
  509.  */
  510. extern time_t       lex_time;
  511.  
  512. int  client_pid;  /* PID of client, that issued actual command */
  513.  
  514. static int  server_id = MASTER_ID,  /* ID of this server   */
  515.             alias_id  = 0;          /* Might be Master-ID  */
  516.  
  517. /* Pointer to the browser-filename of this server
  518.  */
  519. static char *browser_filename = NULL;
  520.  
  521. /* This array should be extended to the following values:
  522.  
  523.    short issued_cmd;    command last issued
  524.    short state;         PENDING, WORKING, COMPLETED
  525.    time_t  last;        time of last message sent
  526.  
  527.    This information should be used for the be_patient-function,
  528.    which informs the clients that the server needs more time to
  529.    finish their requests
  530.  */
  531. static client_pid_array[MAX_CLIENTS];
  532. static short cnt_clients = 0;
  533.  
  534. /* Sends a message to the message queue. If EAGAIN, it waits for 0.1 sec and 
  535.    tries to resend the message until the TIMEOUT elapsed
  536.  */
  537. short send_msg( int cnt, int pos )
  538. { long  elapsed_time = 0;
  539.  
  540.   while( 1 )   
  541.    { if( msgsnd( msqid, (struct msgbuf *) &Msg, cnt, IPC_NOWAIT ) == -1 )
  542.        { if( errno != EAGAIN )
  543.            { fprintf(stderr, "SERVER: (PID: %d, Pos %d) msgsnd failed: errno: %d (%s)\n", 
  544.                              getpid(), pos, errno, strerror(errno) );
  545.              exit( 1 );
  546.             }
  547.          else
  548.           { /* EAGAIN, wait for 0.1 sec and then try again */
  549.             usleep( 100000 );
  550.             elapsed_time += 100;
  551.             if( elapsed_time >= ( SECONDS_TIMEOUT * 1000) )
  552.               { /* Timeout ! Ignore this message
  553.                  */
  554.                 fprintf(stderr, "SERVER: (PID: %d, Pos: %d) Warning: message ignored !\n", 
  555.                              getpid(), pos );
  556.                 return( 1 );
  557.                }
  558.            }
  559.         }
  560.      else
  561.        return( 0 );
  562.     }
  563. }
  564.    
  565.  
  566. /* Used to set the actual name of the browser file in the
  567.    internal data structures (and the one of the master server)
  568.  */
  569. void set_browser_filename(char *filename)
  570. { short cmd;
  571.   int   cnt;
  572.    
  573.   browser_filename = filename;
  574.    
  575.   if( server_id != MASTER_ID && alias_id != MASTER_ID )
  576.     { /* send new browser-file to the master-server
  577.        */
  578.       Msg.mtype = MASTER_ID;
  579.       cmd = CMD_NEW_FILE;
  580.         
  581.       memcpy( Msg.mtext    , &cmd      , sizeof(short) );
  582.       memcpy( Msg.mtext + 4, &server_id, sizeof(short) );
  583.       
  584.       ret_id++;
  585.       memcpy( Msg.mtext + 8, &ret_id, sizeof(short) );
  586.       
  587.       strcpy( Msg.mtext + ARGUMENT_OFFSET, browser_filename );
  588.    
  589.       cnt = ARGUMENT_OFFSET + strlen( Msg.mtext + ARGUMENT_OFFSET ) + 1;
  590.    
  591.       send_msg( cnt, 1 );
  592.      }
  593.   else
  594.     { /* this server is the master, just update the server-table */
  595.       if( s_table[server_id].filename )
  596.         free( s_table[server_id].filename );
  597.       
  598.       s_table[server_id].filename = strdup( browser_filename );
  599.      } 
  600.   }
  601.  
  602. /* This function sends the server-id to the master-server
  603.    telling that this id will not be used anymore
  604.    called by the termination handler
  605.  */
  606. void free_server_id(void)
  607. { short   cmd;
  608.   short   tmp;
  609.   short   i;
  610.   int     cnt;
  611.   long    elapsed_time = 0;
  612.  
  613.   if( server_id == MASTER_ID || alias_id == MASTER_ID )
  614.     { /* Killing of the master-server. If it is the only 
  615.          running server, free message queue, otherwise,
  616.          tell other server to become master
  617.        */
  618.       for( i = MASTER_ID; i < cnt_servers; i++ )
  619.         { if( s_table[i].server_id != 0 && 
  620.               s_table[i].server_id != server_id )
  621.              break;
  622.          }
  623.       if( i == cnt_servers )
  624.         { /* This server is the only one left, now we can delete the ressource
  625.            */
  626.           if( msgctl( msqid, IPC_RMID, 0 ) == -1 )
  627.              { fprintf(stderr, "SERVER: (PID: %d, Pos: 2)Remove MSQ: errno: %d (%s)\n", 
  628.                                  getpid(), errno, strerror(errno) );
  629.                exit( 1 );
  630.               }
  631.           return;
  632.          }
  633.       else
  634.         { /* Master server has to be killed, but there are other servers running.
  635.              choose server i to take the master server part
  636.            */
  637.          
  638.           Msg.mtype = i;
  639.           cmd = CMD_SERVERTABLE;
  640.          
  641.           memcpy( Msg.mtext, &cmd, sizeof(short) );
  642.           memcpy( Msg.mtext + 4, &server_id, sizeof(short) );
  643.          
  644.           for( i = MASTER_ID; i < cnt_servers; i++ )
  645.             { if( s_table[i].server_id &&
  646.                   s_table[i].server_id == server_id )
  647.                 { /* do not send own entry, a deleted entry instead */
  648.                   tmp = 0;
  649.                   memcpy( Msg.mtext + 2 , &tmp, sizeof(short) );
  650.                   strcpy( Msg.mtext + ARGUMENT_OFFSET, "" );
  651.                  }
  652.               else    
  653.                { memcpy( Msg.mtext + 2 , &(s_table[i].server_id), sizeof(short) );
  654.                  if( s_table[i].filename )
  655.                    strcpy( Msg.mtext + ARGUMENT_OFFSET, s_table[i].filename );
  656.                  else
  657.                    strcpy( Msg.mtext + ARGUMENT_OFFSET, "" );
  658.                 }
  659.             
  660.               cnt = strlen(s_table[i].filename) + 1 + ARGUMENT_OFFSET;
  661.  
  662.               ret_id++;
  663.               memcpy( Msg.mtext + 8, &ret_id, sizeof(short) );
  664.          
  665.               send_msg( cnt, 3 );
  666.              }
  667.           
  668.           /* tell new master that the table has been sent completly
  669.            */
  670.           ret_id++;
  671.           memcpy( Msg.mtext + 8, &ret_id, sizeof(short) );
  672.          
  673.           cmd = CMD_S_TABLE_END;
  674.           memcpy( Msg.mtext, &cmd, sizeof(short) );
  675.           send_msg( cnt, 4 );
  676.          
  677.           /* Now we just have to wait for the acknoledgment of the new master
  678.              After this O.K., we are allowed to die !
  679.            */
  680.           while(1)
  681.             { cnt = msgrcv( msqid, (struct msgbuf *) &Msg, 
  682.                      INTRFACE_BUFSIZE, MASTER_ID, IPC_NOWAIT);
  683.               if( cnt < 0 && errno != ENOMSG )
  684.                 { fprintf(stderr, "SERVER: (PID: %d, Pos 5) msgrcv: errno: %d (%s)\n", 
  685.                                getpid(), errno, strerror(errno) );
  686.                   exit( 1 );
  687.                  }
  688.               if( cnt > 0 )
  689.                { cmd = *((short *)Msg.mtext);
  690.                  if( cmd != CMD_S_TABLE_END )
  691.                    { /* wrong command, send back 
  692.                       */
  693.                      send_msg( cnt, 6 );
  694.                     }
  695.                  else
  696.                    { /* New Master sent acknowledgement
  697.                         o.k., we can die now !
  698.                       */
  699.                      return;
  700.                     }
  701.                 }
  702.               usleep( 100000 );
  703.               elapsed_time += 100;
  704.               if( elapsed_time >= (3 * SECONDS_TIMEOUT * 1000) )
  705.                 { /* Timeout ! No Acknowledgment received
  706.                    */
  707.                   fprintf(stderr, "Old Master Server: New Master does not respond !\n");
  708.                   fprintf(stderr, "You should kill all browser programs and delete the message queue\n");
  709.                   fprintf(stderr, "using the ipcrm-command ! \n");
  710.                   fprintf(stderr, "A complete restart is HIGHLY recommended ! \n");
  711.                   return;
  712.                  }
  713.              } /* endwhile */
  714.          }
  715.      }
  716.   else
  717.    { /* Killing of a non master server. Just tell the
  718.         server to free it's server id
  719.       */
  720.      Msg.mtype = MASTER_ID;
  721.      cmd = CMD_SERVERKILL;
  722.       
  723.      memcpy( Msg.mtext,      &cmd,       sizeof(short) );
  724.      memcpy( Msg.mtext + 4 , &server_id, sizeof(short) );
  725.      ret_id++;
  726.      memcpy( Msg.mtext + 8, &ret_id, sizeof(short) );
  727.       
  728.      send_msg( cnt, 7 );
  729.     }
  730.  }
  731.  
  732.  
  733. /* This is the main initializing routine for the servers. If a message-queue
  734.    was already created (detected by init_interface), this routine tries to
  735.    connect to the server. On succes, it set's the server_id to the one re-
  736.    ceived by the master server
  737.  */
  738. int init_server(void)
  739. { static  short first = 1;
  740.   short   cmd, i;
  741.   int     cnt;
  742.   long    elapsed_time = 0;
  743.     
  744.   if( !first )
  745.     return(0);
  746.    
  747.   first = 0;
  748.   if( init_interface() )
  749.     { /* This server is the master. Initialize 
  750.          master-data-structures
  751.        */
  752.       for( i = 0; i < MAX_SERVERS + MASTER_ID; i++ )
  753.         { s_table[i].filename = NULL;
  754.           s_table[i].server_id = 0;
  755.          }
  756.       cnt_servers = MASTER_ID;
  757.       s_table[cnt_servers].server_id = MASTER_ID;
  758.       s_table[cnt_servers].filename  = strdup( browser_filename );
  759.       if( !(s_table[cnt_servers].filename) )
  760.         { fprintf(stderr, "SERVER: (PID: %d, Pos 9): Not enough memory for strdup\n",
  761.                             getpid() );
  762.           exit( 1 );
  763.          }
  764.       
  765.       cnt_servers++;
  766.      }
  767.   else
  768.     { /* This server is NOT the master. Send the browser-filename
  769.          to the server
  770.        */
  771.       Msg.mtype = MASTER_ID;
  772.       cmd = CMD_SERVER;
  773.  
  774.       i = -1;        
  775.       memcpy( Msg.mtext, &cmd, sizeof(short) );
  776.       memcpy( Msg.mtext + 4, &i, sizeof(short) );
  777.  
  778.       ret_id++;
  779.       memcpy( Msg.mtext + 8, &ret_id, sizeof(int) );
  780.       strcpy( Msg.mtext + ARGUMENT_OFFSET, browser_filename );
  781.    
  782.       cnt = ARGUMENT_OFFSET + strlen( Msg.mtext + ARGUMENT_OFFSET ) + 1;
  783.    
  784.       send_msg( cnt, 10 );
  785.       
  786.       /* Now wait for the assigned Server-ID
  787.        */
  788.       while(1)
  789.         { cnt = msgrcv( msqid, (struct msgbuf *) &Msg, 
  790.                  INTRFACE_BUFSIZE, TMP_SERVER_ID, IPC_NOWAIT);
  791.           if( cnt < 0 && errno != ENOMSG )
  792.             { fprintf(stderr, "SERVER: (PID: %d, Pos 11) msgrcv: errno: %d (%s)\n", 
  793.                                   getpid(), errno, strerror(errno) );
  794.               exit( 1 );
  795.              }
  796.           if( cnt > 0 )
  797.            { if( !strcmp( Msg.mtext + ARGUMENT_OFFSET, browser_filename ) )
  798.                { /* the right (same browser-file) message received
  799.                   */
  800.                  server_id = *((short *) Msg.mtext);
  801.                  break;
  802.                 }
  803.              else
  804.                { /* wrong message: send back
  805.                   */
  806.                  send_msg( cnt, 12 );
  807.                 } /* endelse */
  808.             }
  809.           usleep( 100000 );
  810.           elapsed_time += 100;
  811.           if( elapsed_time >= ( 2 * SECONDS_TIMEOUT * 1000) )
  812.             { /* Timeout ! Cannot connect to server 
  813.                */
  814.               fprintf(stderr, "Server: Cannot connect to master server !\n");
  815.               fprintf(stderr, "Maybe there is a message queue left. If there is no other server running,\n");
  816.               fprintf(stderr, "please remove message queue using the ipcrm-command ! \n");
  817.               exit( 1 );
  818.              }
  819.          } /* endwhile */
  820.      } /* endelse not master */
  821.  
  822.   /* define signal handling if server has to terminate
  823.      This handler just removes the ipc-message queue
  824.    */ 
  825.   signal( SIGINT, terminate_handler);
  826.   signal( SIGTERM, terminate_handler);
  827.   signal( SIGHUP, terminate_handler);
  828.   signal (SIGKILL, terminate_handler);
  829.   signal (SIGQUIT, terminate_handler);
  830.  
  831.  }
  832.    
  833.  
  834. static short Is_client( int pid )
  835. { short  i;
  836.    
  837.   for( i = 0; i < cnt_clients; i++ )
  838.     { if( client_pid_array[i] == pid )
  839.         break;
  840.      }
  841.                
  842.   if( i == cnt_clients )
  843.     return( 0 ); /* PID not found: no client ! */
  844.   else
  845.     return( i + 1 ); /* TRUE: pid found */
  846.  }
  847.  
  848.  
  849. /* Wait till a command is sent by a frontend-module. Get this command
  850.    and its arguments
  851.  */
  852. short get_brs_cmd(char *arg1, char *arg2)
  853. { short cmd, i;
  854.   char  *p1, *p2;
  855.   char  ret_arg1[STRINGSIZE];
  856.   static short s_table_received = 0;
  857.       
  858.   int   pid,
  859.         server,
  860.         cnt;
  861.  
  862.   if( first )
  863.     init_server();
  864.    
  865. top: /* if a connect or release-command issued, wait for net message*/
  866.    
  867.   /* get message from message queue: msgflg is set to 0, so this call waits
  868.      untill there's a message or the server receives a signal
  869.    */
  870.   server = server_id;
  871.   while( 1 )
  872.     { cnt = msgrcv( msqid, (struct msgbuf *) &Msg, 
  873.                  INTRFACE_BUFSIZE, server, IPC_NOWAIT);
  874.       if( cnt < 0 && errno != ENOMSG )
  875.         { fprintf(stderr, "SERVER: (PID: %d, Pos 14) msgrcv: errno: %d (%s)\n", 
  876.                      getpid(), errno, strerror(errno) );
  877.           exit( 1 );
  878.          }
  879.       if( cnt >= 0 )
  880.          break;
  881.       server = ( (server == server_id) && alias_id) ? alias_id : server_id ;
  882.       usleep( 100000 );
  883.      }
  884.  
  885.   cmd    = *((short *) Msg.mtext);
  886.   pid    = *((int *)(Msg.mtext + 4));
  887.   cmd_id = *((int *)(Msg.mtext + 8));
  888.  
  889.   switch( cmd )
  890.    { case CMD_CONNECT:     /* commands issued by a server, not a client */ 
  891.      case CMD_SERVER: 
  892.      case CMD_SERVERKILL:
  893.      case CMD_SERVERTABLE: 
  894.      case CMD_S_TABLE_END: 
  895.      case CMD_NEW_FILE:        break;
  896.  
  897.      case CMD_SERVER_ID:   /* command may be issued by any client */
  898.                                break;
  899.  
  900.       
  901.      default: if( pid && !Is_client( pid ) )
  902.                 { /* Client not known: ignore message ! */
  903.                   fprintf(stderr, "Server (PID %d) Warning: Unknown Client (pid ? %d)\n", 
  904.                             getpid(), pid);
  905.                   goto top;
  906.                  }
  907.     }
  908.  
  909.   cmd_msg_flag = cmd & 0x7f;
  910.  
  911.   p1 = NULL;
  912.   p2 = NULL;
  913.  
  914.   switch(cmd)
  915.    {  /* Commands, which have no arguments:
  916.        */
  917.       case CMD_FUNCTIONS: /* Return all functions defined in the project  */
  918.                           /* Arguments: none                              */
  919.       case CMD_VARIABLES: /* Return all global (and static) variables     */
  920.                           /* defined in the project                       */
  921.                           /* Arguments: none                              */
  922.       case CMD_ENUMS:     /* Return all enums, structs, unions and        */
  923.       case CMD_STRUCTS:   /* typedefs                                     */
  924.       case CMD_UNIONS:
  925.       case CMD_TYPEDEFS:
  926.       case CMD_FILES:
  927.       case CMD_MACROS:
  928.            break;
  929.       
  930.       /* Commands, which have one argument:
  931.        */
  932.       case CMD_INIT:   /* Init the Browser, Arguments: <Browser-File> */
  933.       case CMD_FILE:      /* Return Module, where FILE belongs to         */
  934.                           /* Args: <filename>                             */
  935.       case CMD_INCLUDES:  /* Return Files, that are includes in that      */
  936.                           /* given file                                   */
  937.                           /* Args: <filename>                             */
  938.       case CMD_REFERENCE:
  939.       case CMD_WORK_DIR:  /* Working directory of a file in the project   */
  940.                           /* Args: <filename>                             */
  941.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  942.            break;
  943.  
  944.       /* Commands, which have two arguments:
  945.        */
  946.       case CMD_CALLS:  /* Get function-calls of a target-function     */
  947.                        /* Args: <target-funct> [,<target-funct-file>] */
  948.       case CMD_CALLED_BY: /* Get functions that call target-function     */
  949.                           /* Args: <target-funct> [,<target-funct-file>] */
  950.       case CMD_CALLS_ONCE:
  951.       case CMD_CALLED_BY_ONCE:
  952.                           /* Args: <target-funct> [,<target-funct-file>] */
  953.       case CMD_FUNCT_POS: /* Get position (file, line) of target-function */
  954.                           /* Args: <target-funct> [,<target-funct-file>]  */
  955.       case CMD_VAR_POS:   /* Get position (file, line) of target-variable */
  956.                           /* Args: <target-var> [,<target-funct-file>]    */
  957.       case CMD_MACRO_POS: /* Get position (file, line) of target-macro    */
  958.                           /* Args: <target-macro> [,<target-macro-file>]  */
  959.       case CMD_USES:      /* List usage of global variable in target      */
  960.                           /* Args: <target-funct> [,<target-funct-file>]  */
  961.       case CMD_USES_ALL:  /* List usage of all vars in target-function    */
  962.                           /* Args: <target-funct> [,<target-funct-file>]  */
  963.       case CMD_USED_BY:   /* List function that use target-variable       */
  964.                           /* Args: <target-var> [,<target-funct-file>]    */
  965.       case CMD_DEF_POS:
  966.       case CMD_USES_ONCE:
  967.       case CMD_USED_BY_ONCE:
  968.       case CMD_REFERENCE_F:
  969.       case CMD_REFERENCE_V:
  970.       case CMD_WHAT_IS:
  971.    
  972.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  973.            p2 = strtok( NULL, "," );
  974.            break;
  975.          
  976.       case CMD_CONNECT:   /* Client requests connection to server */
  977.       
  978.            if( cnt_clients == MAX_CLIENTS )
  979.              { /* send refused */
  980.                send_brs_ret( RET_REFUSED, 0,  pid, 
  981.                              "Too many clients", "", "", "" );
  982.               }
  983.            else
  984.              { /* connection established, add pid to table, if
  985.                   not allready in there
  986.                 */
  987.                sprintf(ret_arg1,"%ld", (long)lex_time * 2);
  988.                if( !Is_client( pid ) )
  989.                  { client_pid_array[cnt_clients++] = pid;
  990.                    send_brs_ret( RET_CONNECT, 0,  pid, ret_arg1, "", "", "" );
  991.                   }
  992.                else
  993.                  { /* allready connected */
  994.                    send_brs_ret( RET_CONNECT, 1,  pid, ret_arg1, "", "", "" );
  995.                   }
  996.               }
  997.       
  998.            goto  top;
  999.    
  1000.       case CMD_TABLE:  /* send server-table to client */
  1001.    
  1002.            for( i = MASTER_ID; i < cnt_servers; i++ )
  1003.              { send_brs_ret( RET_FILE, s_table[i].server_id,  pid, 
  1004.                 (s_table[i].filename) ? s_table[i].filename : "", "", "", "" );
  1005.               }
  1006.            send_brs_ret( RET_END, 0,  pid, "", "", "", "" );
  1007.             
  1008.            goto  top;
  1009.    
  1010.       case CMD_RELEASE:
  1011.       
  1012.            if( cnt_clients == 0 )
  1013.              { /* send refused */
  1014.                send_brs_ret( RET_REFUSED, 0,  pid, 
  1015.                              "No Client", "", "", "" );
  1016.               }
  1017.            else
  1018.              { for( i = 0; i < cnt_clients; i++ )
  1019.                 { if( client_pid_array[i] == pid )
  1020.                     break;
  1021.                  }
  1022.                
  1023.                if( i == cnt_clients )
  1024.                  { send_brs_ret( RET_REFUSED, 0,  pid, 
  1025.                              "No Client", "", "", "" );
  1026.                   }
  1027.                else
  1028.                  { client_pid_array[i] = client_pid_array[cnt_clients-1];
  1029.                    cnt_clients--;
  1030.                   }
  1031.               }
  1032.       
  1033.            goto  top;
  1034.  
  1035.       case CMD_TERMINATE:   /* Kill server */
  1036.       
  1037.            if( s_table_received )
  1038.             { /* the master server is sending the new server table.
  1039.                  while this is going on, ignore the request for
  1040.                  termination and push it back to the queue for later
  1041.                  processing
  1042.                */
  1043.               send_msg( cnt, 16 );
  1044.       
  1045.               goto top;
  1046.               }
  1047.    
  1048.            free_server_id();   
  1049.            fprintf(stderr, "SERVER: (PID: %d) Terminate as requested\n",
  1050.                               getpid() );
  1051.            exit( 0 );
  1052.    
  1053.       case CMD_ABORT: break; /* currently unimplemented */
  1054.    
  1055.       case CMD_SERVER: /* a server requests a server-id */
  1056.    
  1057.            /* find free server-id
  1058.             */
  1059.            for( i = MASTER_ID + 1; i < cnt_servers; i++ )
  1060.              { if( s_table[i].server_id == 0 )
  1061.                   break;
  1062.               }
  1063.    
  1064.            /* create server entry
  1065.             */
  1066.            s_table[i].server_id = i;
  1067.            s_table[i].filename  = strdup( Msg.mtext + ARGUMENT_OFFSET );
  1068.            if( !(s_table[i].filename) )
  1069.              { fprintf(stderr, "SERVER: (PID: %d, Pos 15): Not enough memory for strdup\n",
  1070.                                  getpid() );
  1071.                exit( 1 );
  1072.               }
  1073.            if( i == cnt_servers )
  1074.              cnt_servers++;
  1075.    
  1076.            /* send the new server id to this server
  1077.             */
  1078.            Msg.mtype = TMP_SERVER_ID;
  1079.            memcpy( Msg.mtext, &i, sizeof(short) );
  1080.            memcpy( Msg.mtext + 4, &server_id, sizeof(short) );
  1081.            ret_id++;
  1082.            memcpy( Msg.mtext + 8, &ret_id, sizeof(int) );
  1083.    
  1084.            send_msg( cnt, 17 );
  1085.    
  1086.            goto top;
  1087.            
  1088.       case CMD_SERVERKILL: /* a server is freeing his server-id */
  1089.    
  1090.            /* find this server-id
  1091.             */
  1092.            for( i = MASTER_ID; i < cnt_servers; i++ )
  1093.              { if( s_table[i].server_id ==  pid )
  1094.                   break;
  1095.               }
  1096.            if( i == cnt_servers )
  1097.              { fprintf(stderr, "SERVER: (PID: %d) Unknown Server (%hd) requests killing\n", 
  1098.                                 getpid(), pid );
  1099.                break;
  1100.               }
  1101.            s_table[i].server_id = 0;
  1102.            free( s_table[i].filename );
  1103.            s_table[i].filename = NULL;
  1104.  
  1105.            goto top;
  1106.      
  1107.       case CMD_SERVER_ID: /* a client want's to know a server id */
  1108.  
  1109.            if( server != MASTER_ID )
  1110.              { /* This request can only be sent to a master
  1111.                 */
  1112.                send_brs_ret( RET_ERROR, 0,  pid, "Wrong server", "", "", "" );
  1113.                break;
  1114.               }
  1115.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1116.    
  1117.            /* find matching browser file
  1118.             */
  1119.            for( i = 0; i < cnt_servers; i++ )
  1120.              { if( s_table[i].server_id && !strcmp( s_table[i].filename, p1) )
  1121.                   break;
  1122.               }
  1123.    
  1124.            if( i == cnt_servers )
  1125.              { /* server with specified browserfile not found
  1126.                   send error message
  1127.                 */
  1128.                send_brs_ret( RET_ERROR, 0,  pid, "Unknown browser file", "", "", "" );
  1129.                break;
  1130.               }
  1131.    
  1132.            send_brs_ret( RET_SERVER_ID, s_table[i].server_id,  pid, "", "", "", "" );
  1133.    
  1134.            goto top;
  1135.      
  1136.       case CMD_SERVERTABLE: /* old master sends its server table */
  1137.    
  1138.            s_table[cnt_servers].server_id = *((short *)(Msg.mtext + 2));
  1139.            if( s_table[cnt_servers].server_id )
  1140.               s_table[cnt_servers].filename = strdup( Msg.mtext + ARGUMENT_OFFSET);
  1141.            else
  1142.               s_table[cnt_servers].filename = NULL;
  1143.    
  1144.            cnt_servers++;
  1145.            s_table_received = 1;
  1146.  
  1147.            goto top;
  1148.   
  1149.       case CMD_S_TABLE_END: /* server-table is now complete: send acknowledgment */
  1150.            if( s_table_received )
  1151.              { /* we got this command right after the server-table, send 
  1152.                   acknoledgment now
  1153.                 */
  1154.                s_table_received = 0;
  1155.                Msg.mtype = MASTER_ID;
  1156.                ret_id++;
  1157.                memcpy( Msg.mtext + 4, &server_id, sizeof(int) );
  1158.                memcpy( Msg.mtext + 8, &ret_id, sizeof(int) );
  1159.                send_msg( cnt, 18 );
  1160.       
  1161.                /* This server is now the master 
  1162.                 */
  1163.                alias_id = MASTER_ID;
  1164.               }
  1165.            else
  1166.              { /* we got this message accidentially, it is intented for
  1167.                   the old master. Send it back !
  1168.                 */
  1169.                send_msg( cnt, 19 );
  1170.               }
  1171.    
  1172.            usleep( 100000 );
  1173.    
  1174.            goto top;
  1175.  
  1176.            
  1177.       case CMD_NEW_FILE:
  1178.            i = *((short *) Msg.mtext + 4);
  1179.  
  1180.            if( s_table[i].filename )
  1181.              free( s_table[i].filename );
  1182.            s_table[i].filename  = strdup( Msg.mtext + ARGUMENT_OFFSET );
  1183.            if( !(s_table[i].filename) )
  1184.              { fprintf(stderr, "SERVER: (PID: %d, Pos 19): Not enough memory for strdup\n",
  1185.                                 getpid() );
  1186.                exit( 1 );
  1187.               }
  1188.    
  1189.            goto top;
  1190.    
  1191.       default:
  1192.            send_brs_ret( RET_CMD_UNKNOWN, cmd,  pid, "", "", "", "" );
  1193.            goto top;
  1194.            break;
  1195.      }
  1196.  
  1197.   arg1[0] = 0;
  1198.   arg2[0] = 0;
  1199.  
  1200.   if( p1 )
  1201.     { if( strlen( p1 ) > STRINGSIZE )
  1202.         { strncpy( arg1, p1, STRINGSIZE-1 );
  1203.           arg1[STRINGSIZE-1] = 0;
  1204.          }
  1205.       else
  1206.          strcpy( arg1, p1 );
  1207.      }
  1208.   else
  1209.      strcpy( arg1, "" );
  1210.  
  1211.   if( p2 )
  1212.     { if( strlen( p2 ) > STRINGSIZE )
  1213.         { strncpy( arg2, p2, STRINGSIZE-1 );
  1214.           arg2[STRINGSIZE-1] = 0;
  1215.          }
  1216.       else
  1217.          strcpy( arg2, p2 );
  1218.      }
  1219.   else
  1220.      strcpy( arg2, "" );
  1221.  
  1222.   client_pid = pid;
  1223.  
  1224.   return( cmd );
  1225.  }
  1226.  
  1227.  
  1228. /* Returns the result of the request to the client process
  1229.  */
  1230. void send_brs_ret( short ret_code, short flag, int pid, 
  1231.                    char * arg1, char *arg2, char *arg3, char *arg4 )
  1232. { short cmd;
  1233.   short cnt;
  1234.  
  1235.   if( first )
  1236.     init_interface();
  1237.  
  1238.   Msg.mtype = (pid & 0x00ffffff) | ((int)(cmd_msg_flag & 0x7f) << 24);
  1239.   ret_id++;
  1240.   
  1241.   memcpy( Msg.mtext, &ret_code, sizeof(short) );
  1242.   memcpy( Msg.mtext + 2, &flag, sizeof(short) );
  1243.   memcpy( Msg.mtext + 4, &server_id, sizeof(int) );
  1244.   memcpy( Msg.mtext + 8, &ret_id, sizeof(int) );
  1245.  
  1246.   /* Test, if buffer is able to hold date:
  1247.      length of strings + 3 Bytes ',' + 1 Byte '\0' + ARGUMENT_OFFSET
  1248.    */
  1249.   cnt = strlen(arg1) + strlen(arg2) + strlen(arg3) + 
  1250.         strlen(arg4) + 4 + ARGUMENT_OFFSET;
  1251.    
  1252.   if( cnt > INTRFACE_BUFSIZE )
  1253.     { fprintf( stderr, "Data to transfer exceeds buffersize !\n" );
  1254.       exit(1);
  1255.      }
  1256.  
  1257.   /* Copy arguments to buffer, separated by ','
  1258.    */
  1259.   if( arg4[0] )
  1260.     sprintf( Msg.mtext + ARGUMENT_OFFSET, "%s,%s,%s,%s", 
  1261.                                          arg1, arg2, arg3, arg4 );
  1262.   else if( arg3[0] )
  1263.     sprintf( Msg.mtext + ARGUMENT_OFFSET, "%s,%s,%s"   , 
  1264.                                          arg1, arg2, arg3 );
  1265.   else if( arg2[0] )
  1266.     sprintf( Msg.mtext + ARGUMENT_OFFSET, "%s,%s"      , 
  1267.                                          arg1, arg2 );
  1268.   else if( arg1[0] )
  1269.     sprintf( Msg.mtext + ARGUMENT_OFFSET, "%s"         , 
  1270.                                          arg1 );
  1271.   else
  1272.     strcpy( Msg.mtext + ARGUMENT_OFFSET, "" );
  1273.    
  1274.   cnt = ARGUMENT_OFFSET + strlen( Msg.mtext + ARGUMENT_OFFSET ) + 1;
  1275.    
  1276.   send_msg( cnt, 20 );
  1277.  }
  1278.  
  1279.  
  1280. /* Handler for SIGINT and SIGTERM
  1281.  
  1282.    Just remove the IPC-message queue
  1283.  
  1284.  */
  1285. void  terminate_handler(int sig)
  1286. {
  1287.    free_server_id();  
  1288.    fprintf(stderr, "SERVER: (PID: %d): Interrupted\n", getpid() );
  1289.    exit( 0 );
  1290.  }
  1291.  
  1292.  
  1293. /*********************************************************************
  1294. **********************************************************************
  1295.  
  1296. THIS PART OF THE CODE ARE THE MAIN INTERFACING ROUTINES FOR THE CLIENT
  1297.  
  1298. **********************************************************************
  1299. *********************************************************************/
  1300.  
  1301. #else  /* BRS_CLIENT */
  1302.  
  1303. long  cmd_id = 0;
  1304. long  ret_id = 0;
  1305.  
  1306. int  timeout_value = SECONDS_TIMEOUT;
  1307.  
  1308. /* Sends a message to the message queue. If EAGAIN, it waits for 0.1 sec and 
  1309.    tries to resend the message until the TIMEOUT elapsed
  1310.    THIS IS THE CLIENT VERSION
  1311.  */
  1312. short send_msg( int cnt, int pos )
  1313. { long  elapsed_time = 0;
  1314.  
  1315.   while( 1 )   
  1316.    { if( msgsnd( msqid, (struct msgbuf *) &Msg, cnt, IPC_NOWAIT ) == -1 )
  1317.        { if( errno != EAGAIN )
  1318.            { fprintf(stderr, "CLIENT: (PID: %d, Pos %d) msgsnd failed: errno: %d (%s)\n", 
  1319.                              getpid(), pos, errno, strerror(errno) );
  1320.              exit( 1 );
  1321.             }
  1322.          else
  1323.           { /* EAGAIN, wait for 0.1 sec and then try again */
  1324.             usleep( 100000 );
  1325.             elapsed_time += 100;
  1326.             if( elapsed_time >= ( SECONDS_TIMEOUT * 1000) )
  1327.               { /* Timeout ! Ignore this message
  1328.                  */
  1329.                 fprintf(stderr, "CLIENT: (PID: %d, Pos: %d) Warning: message ignored !\n", 
  1330.                              getpid(), pos );
  1331.                 return( 1 );
  1332.                }
  1333.            }
  1334.         }
  1335.      else
  1336.        return( 0 );
  1337.     }
  1338. }
  1339.  
  1340. /* Wait till a return is sent by server. Get return-code
  1341.    the flag (if r_flag != NULL) and arguments
  1342.  */
  1343. short get_brs_ret(short command, int * server, short *r_flag, 
  1344.                   char *arg1, char *arg2, char *arg3, char *arg4)
  1345. { short cmd, flag;
  1346.   char  *p1, *p2, *p3, *p4;
  1347.   int   pid,
  1348.         msg_type,
  1349.         server_id,
  1350.         cnt;
  1351.   long  elapsed_time = 0; /* in milliseconds */
  1352.  
  1353.   if( first )
  1354.     init_interface();
  1355.  
  1356.   pid = getpid();
  1357.    
  1358.   msg_type = (pid & 0xffffff) | ((int)(command & 0x7f) << 24);
  1359.       
  1360.   /* get message from message queue: try to get the message 
  1361.    */
  1362.   while( 1 )
  1363.     { cnt = msgrcv( msqid, (struct msgbuf *) &Msg, 
  1364.                  INTRFACE_BUFSIZE, msg_type, IPC_NOWAIT);
  1365.       if( cnt == -1 )
  1366.         { /* message not found wait for 100.000 micro-seconds 
  1367.              equals 0.1 seconds
  1368.            */
  1369.           usleep( 100000 );
  1370.           elapsed_time += 100;
  1371.           if( elapsed_time >= (timeout_value * 1000) )
  1372.             return( RET_TIMEOUT );
  1373.          }
  1374.       else
  1375.         break;
  1376.      }
  1377.    
  1378.  
  1379.   cmd       = *((short *) Msg.mtext    );
  1380.    
  1381.   /* here goes the test if the Server sent the be_patient-return.
  1382.    
  1383.      if so, call the (possibly) user defined function and 
  1384.      abort this command if this functions returns nonzero
  1385.    
  1386.      - currently unimplemented
  1387.    
  1388.    if( cmd == RET_PLEACE_WAIT )
  1389.      { erg = (*be_patient_user)();
  1390.        if( erg )
  1391.          { sent_brs_cmd( CMD_ABORT, ...)
  1392.            return
  1393.           }
  1394.        elapsed_time = 0;
  1395.        goto while_
  1396.      }
  1397.    */
  1398.   flag      = *((short *) (Msg.mtext + 2) );
  1399.   server_id = *((int   *) (Msg.mtext + 4) );
  1400.   ret_id    = *((int   *) (Msg.mtext + 8) );
  1401.    
  1402.   if( r_flag )
  1403.     *r_flag = flag;
  1404.  
  1405.   /* printf("cmd: %hd, flag %hx, server-id: %ld\n", cmd, flag, server_id ); */
  1406.    
  1407.  
  1408.   p1 = NULL;
  1409.   p2 = NULL;
  1410.   p3 = NULL;
  1411.   p4 = NULL;
  1412.  
  1413.   switch(cmd)
  1414.    {  case RET_FILE:
  1415.       case RET_ERROR:
  1416.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1417.            if( flag & 0x01 )
  1418.               /* module given */
  1419.               p2 = strtok( NULL, "," );
  1420.            break;
  1421.  
  1422.       case RET_FUNCT:
  1423.       case RET_VAR:
  1424.       case RET_L_VAR:
  1425.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1426.            if( !(flag & 0x01) )
  1427.              { /* position is given
  1428.                 */
  1429.                p2 = strtok( NULL, "," );
  1430.                p3 = strtok( NULL, "," );
  1431.                if( !(flag & 0x02) )
  1432.                   /* module given */
  1433.                   p4 = strtok( NULL, "," );
  1434.               }
  1435.            break;
  1436.          
  1437.       case RET_STRUCT:
  1438.       case RET_UNION:
  1439.       case RET_ENUM:
  1440.       case RET_TYPEDEF:
  1441.       case RET_MACRO:
  1442.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1443.            if( !(flag & 0x01) )
  1444.              { /* position is given
  1445.                 */
  1446.                p2 = strtok( NULL, "," );
  1447.                p3 = strtok( NULL, "," );
  1448.                /* module ignored */
  1449.               }
  1450.            break;
  1451.       
  1452.       case RET_REFERENCE:
  1453.       case RET_COMP:
  1454.       case RET_ENUM_C:
  1455.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1456.            p2 = strtok( NULL, "," );
  1457.            p3 = strtok( NULL, "," );
  1458.            break;
  1459.  
  1460.       case RET_POS:
  1461.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1462.            p2 = strtok( NULL, "," );
  1463.            if( flag & 0x01 )
  1464.              { /* module is given
  1465.                 */
  1466.                p3 = strtok( NULL, "," );
  1467.               }
  1468.            break;
  1469.  
  1470.       case RET_FPOS:
  1471.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1472.            p2 = strtok( NULL, "," );
  1473.            p3 = strtok( NULL, "," );
  1474.            if( flag & 0x01 )
  1475.              { /* module is given
  1476.                 */
  1477.                p4 = strtok( NULL, "," );
  1478.               }
  1479.            break;
  1480.       
  1481.       case RET_CONNECT: /* should also send a version-string to client */
  1482.                         /* currently not implemented                   */
  1483.       case RET_REFUSED:
  1484.       case RET_DIR:     /* working directory - just 1 argument */
  1485.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1486.            break;
  1487.  
  1488.       case RET_END:
  1489.       case RET_OK:
  1490.       case RET_CMD_UNKNOWN:
  1491.       case RET_PLEASE_WAIT: /* currently not implemented */
  1492.            break;
  1493.  
  1494.       default:
  1495.            return( cmd ); /* unknown command */
  1496.            break;
  1497.      }
  1498.  
  1499.   arg1[0] = 0;
  1500.   arg2[0] = 0;
  1501.   arg3[0] = 0;
  1502.   arg4[0] = 0;
  1503.  
  1504.   if( p1 )
  1505.     { if( strlen( p1 ) > STRINGSIZE )
  1506.         { strncpy( arg1, p1, STRINGSIZE-1 );
  1507.           arg1[STRINGSIZE-1] = 0;
  1508.          }
  1509.       else
  1510.          strcpy( arg1, p1 );
  1511.      }
  1512.   else
  1513.      strcpy( arg1, "" );
  1514.  
  1515.   if( p2 )
  1516.     { if( strlen( p2 ) > STRINGSIZE )
  1517.         { strncpy( arg2, p2, STRINGSIZE-1 );
  1518.           arg2[STRINGSIZE-1] = 0;
  1519.          }
  1520.       else
  1521.          strcpy( arg2, p2 );
  1522.      }
  1523.   else
  1524.      strcpy( arg2, "" );
  1525.  
  1526.   if( p3 )
  1527.     { if( strlen( p3 ) > STRINGSIZE )
  1528.         { strncpy( arg3, p3, STRINGSIZE-1 );
  1529.           arg3[STRINGSIZE-1] = 0;
  1530.          }
  1531.       else
  1532.          strcpy( arg3, p3 );
  1533.      }
  1534.   else
  1535.      strcpy( arg3, "" );
  1536.  
  1537.   if( p4 )
  1538.     { if( strlen( p4 ) > STRINGSIZE )
  1539.         { strncpy( arg4, p4, STRINGSIZE-1 );
  1540.           arg2[STRINGSIZE-1] = 0;
  1541.          }
  1542.       else
  1543.          strcpy( arg4, p4 );
  1544.      }
  1545.   else
  1546.      strcpy( arg4, "" );
  1547.  
  1548.   return( cmd );
  1549.  }
  1550.  
  1551.  
  1552.  
  1553. void send_brs_cmd( int server, short ret_code, short flag, char * arg1, char *arg2)
  1554. { short cmd;
  1555.   short cnt;
  1556.   int   pid;
  1557.    
  1558.   if( first )
  1559.     init_interface();
  1560.   
  1561.   pid = getpid();
  1562.    
  1563.   /* message goes to server : 
  1564.    */
  1565.   Msg.mtype = server;
  1566.    
  1567.   cmd_id++;
  1568.     
  1569.   memcpy( Msg.mtext, &ret_code, sizeof(short) );
  1570.   memcpy( Msg.mtext + 2, &flag, sizeof(short) );
  1571.   memcpy( Msg.mtext + 4, &pid , sizeof(int) );
  1572.   memcpy( Msg.mtext + 8, &cmd_id, sizeof(int) );
  1573.  
  1574.   /* Test, if buffer is able to hold date:
  1575.      length of strings + 1 Byte ',' + 1 Byte '\0' + ARGUMENT_OFFSET
  1576.    */
  1577.   cnt = strlen(arg1) + strlen(arg2) + 2 + ARGUMENT_OFFSET;
  1578.    
  1579.   if( cnt > INTRFACE_BUFSIZE )
  1580.     { fprintf( stderr, "Data to transfer exceeds buffersize !\n" );
  1581.       exit(1);
  1582.      }
  1583.  
  1584.   /* Copy arguments to buffer, separated by ','
  1585.    */
  1586.   if( arg2[0] )
  1587.     sprintf( Msg.mtext + ARGUMENT_OFFSET, "%s,%s"      , arg1, arg2 );
  1588.   else if( arg1[0] )
  1589.     sprintf( Msg.mtext + ARGUMENT_OFFSET, "%s"         , arg1 );
  1590.   else
  1591.     strcpy(  Msg.mtext + ARGUMENT_OFFSET, "" );
  1592.  
  1593.   cnt = ARGUMENT_OFFSET + strlen( Msg.mtext + ARGUMENT_OFFSET ) + 1;
  1594.    
  1595.   send_msg( cnt, 0 );
  1596.  }
  1597.  
  1598.  
  1599. /* get messages in queue 
  1600.  */
  1601. short brs_get_msg_debug(short command, int * server, int *pid, short *ret_cmd, int *ret_id, 
  1602.                     short *r_flag, char *arg1, 
  1603.                     char *arg2, char *arg3, char *arg4)
  1604. { short cmd, flag;
  1605.   char  *p1, *p2, *p3, *p4;
  1606.   int   server_id,
  1607.         msg_type,
  1608.         cnt;
  1609.   long  elapsed_time = 0; /* in milliseconds */
  1610.  
  1611.   if( first )
  1612.     init_interface();
  1613.  
  1614.   if( command == 0 )
  1615.     msg_type = 0;
  1616.   else
  1617.     msg_type = (*pid & 0xffffff) | ((int)(command & 0x7f) << 24);
  1618.  
  1619.   /* get message from message queue: try to get the message 
  1620.    */
  1621.   while( 1 )
  1622.     { cnt = msgrcv( msqid, (struct msgbuf *) &Msg, 
  1623.                  INTRFACE_BUFSIZE, msg_type, IPC_NOWAIT);
  1624.       if( cnt == -1 )
  1625.         { return( RET_TIMEOUT );
  1626.          }
  1627.       else
  1628.         break;
  1629.      }
  1630.    
  1631.   if( command == 0 )
  1632.     { /* get command and pid */
  1633.       if( pid)
  1634.         *pid = Msg.mtype & 0x00ffffff;
  1635.       if( ret_cmd )
  1636.         *ret_cmd = (Msg.mtype & 0xff000000) >> 24;
  1637.      }
  1638.       
  1639.   cmd        = *((short *) Msg.mtext    );
  1640.    
  1641.   flag       = *((short *) (Msg.mtext + 2) );
  1642.   *server    = *((int   *) (Msg.mtext + 4) );
  1643.   *ret_id    = *((int   *) (Msg.mtext + 8) );
  1644.    
  1645.   if( r_flag )
  1646.     *r_flag = flag;
  1647.  
  1648.   /* printf("cmd: %hd, flag %hx, server-id: %ld\n", cmd, flag, server_id ); */
  1649.    
  1650.  
  1651.   p1 = NULL;
  1652.   p2 = NULL;
  1653.   p3 = NULL;
  1654.   p4 = NULL;
  1655.  
  1656.   switch(cmd)
  1657.    {  case RET_FILE:
  1658.       case RET_ERROR:
  1659.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1660.            if( flag & 0x01 )
  1661.               /* module given */
  1662.               p2 = strtok( NULL, "," );
  1663.            break;
  1664.  
  1665.       case RET_FUNCT:
  1666.       case RET_VAR:
  1667.       case RET_L_VAR:
  1668.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1669.            if( !(flag & 0x01) )
  1670.              { /* position is given
  1671.                 */
  1672.                p2 = strtok( NULL, "," );
  1673.                p3 = strtok( NULL, "," );
  1674.                if( !(flag & 0x02) )
  1675.                   /* module given */
  1676.                   p4 = strtok( NULL, "," );
  1677.               }
  1678.            break;
  1679.          
  1680.       case RET_STRUCT:
  1681.       case RET_UNION:
  1682.       case RET_ENUM:
  1683.       case RET_TYPEDEF:
  1684.       case RET_MACRO:
  1685.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1686.            if( !(flag & 0x01) )
  1687.              { /* position is given
  1688.                 */
  1689.                p2 = strtok( NULL, "," );
  1690.                p3 = strtok( NULL, "," );
  1691.                /* module ignored */
  1692.               }
  1693.            break;
  1694.  
  1695.       case RET_POS:
  1696.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1697.            p2 = strtok( NULL, "," );
  1698.            if( flag & 0x01 )
  1699.              { /* module is given
  1700.                 */
  1701.                p3 = strtok( NULL, "," );
  1702.               }
  1703.            break;
  1704.       
  1705.       case RET_REFERENCE:
  1706.       case RET_ENUM_C:
  1707.       case RET_COMP:
  1708.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1709.            p2 = strtok( NULL, "," );
  1710.            p3 = strtok( NULL, "," );
  1711.            break;
  1712.  
  1713.       case RET_CONNECT: /* should also send a version-string to client */
  1714.                         /* currently not implemented                   */
  1715.       case RET_REFUSED:
  1716.       case RET_DIR:     /* working directory - just 1 argument */
  1717.            p1 = strtok( Msg.mtext + ARGUMENT_OFFSET, "," );
  1718.            break;
  1719.  
  1720.       case RET_END:
  1721.       case RET_OK:
  1722.       case RET_CMD_UNKNOWN:
  1723.       case RET_PLEASE_WAIT: /* currently not implemented */
  1724.            break;
  1725.  
  1726.       default:
  1727.            return( cmd ); /* unknown command */
  1728.            break;
  1729.      }
  1730.  
  1731.   arg1[0] = 0;
  1732.   arg2[0] = 0;
  1733.   arg3[0] = 0;
  1734.   arg4[0] = 0;
  1735.  
  1736.   if( p1 )
  1737.     { if( strlen( p1 ) > STRINGSIZE )
  1738.         { strncpy( arg1, p1, STRINGSIZE-1 );
  1739.           arg1[STRINGSIZE-1] = 0;
  1740.          }
  1741.       else
  1742.          strcpy( arg1, p1 );
  1743.      }
  1744.   else
  1745.      strcpy( arg1, "" );
  1746.  
  1747.   if( p2 )
  1748.     { if( strlen( p2 ) > STRINGSIZE )
  1749.         { strncpy( arg2, p2, STRINGSIZE-1 );
  1750.           arg2[STRINGSIZE-1] = 0;
  1751.          }
  1752.       else
  1753.          strcpy( arg2, p2 );
  1754.      }
  1755.   else
  1756.      strcpy( arg2, "" );
  1757.  
  1758.   if( p3 )
  1759.     { if( strlen( p3 ) > STRINGSIZE )
  1760.         { strncpy( arg3, p3, STRINGSIZE-1 );
  1761.           arg3[STRINGSIZE-1] = 0;
  1762.          }
  1763.       else
  1764.          strcpy( arg3, p3 );
  1765.      }
  1766.   else
  1767.      strcpy( arg3, "" );
  1768.  
  1769.   if( p4 )
  1770.     { if( strlen( p4 ) > STRINGSIZE )
  1771.         { strncpy( arg4, p4, STRINGSIZE-1 );
  1772.           arg2[STRINGSIZE-1] = 0;
  1773.          }
  1774.       else
  1775.          strcpy( arg4, p4 );
  1776.      }
  1777.   else
  1778.      strcpy( arg4, "" );
  1779.  
  1780.   return( cmd );
  1781.  }
  1782.  
  1783.  
  1784. #endif /* CLIENT */
  1785.  
  1786.